//! src/isa/inst.rs
//! 
//! # RISC-V 指令定义与译码器

use crate::common::SimError;

/// 使用 enum 表示所有我们支持的 RISC-V 指令。
/// 每个变体都包含了它执行所需的所有字段，这使得 execute 函数中的 match 语句非常清晰。
#[derive(Debug, PartialEq)] // 添加 PartialEq 以便在测试中断言
pub enum Instruction {
    // RV32I Base Instruction Set
    LUI    { rd: usize, imm: i32 },
    AUIPC  { rd: usize, imm: i32 },
    JAL    { rd: usize, imm: i32 },
    JALR   { rd: usize, rs1: usize, imm: i32 },
    BEQ    { rs1: usize, rs2: usize, imm: i32 },
    BNE    { rs1: usize, rs2: usize, imm: i32 },
    BLT    { rs1: usize, rs2: usize, imm: i32 },
    BGE    { rs1: usize, rs2: usize, imm: i32 },
    BLTU   { rs1: usize, rs2: usize, imm: i32 },
    BGEU   { rs1: usize, rs2: usize, imm: i32 },
    LB     { rd: usize, rs1: usize, imm: i32 },
    LH     { rd: usize, rs1: usize, imm: i32 },
    LW     { rd: usize, rs1: usize, imm: i32 },
    LBU    { rd: usize, rs1: usize, imm: i32 },
    LHU    { rd: usize, rs1: usize, imm: i32 },
    SB     { rs1: usize, rs2: usize, imm: i32 },
    SH     { rs1: usize, rs2: usize, imm: i32 },
    SW     { rs1: usize, rs2: usize, imm: i32 },
    ADDI   { rd: usize, rs1: usize, imm: i32 },
    SLTI   { rd: usize, rs1: usize, imm: i32 },
    SLTIU  { rd: usize, rs1: usize, imm: i32 },
    XORI   { rd: usize, rs1: usize, imm: i32 },
    ORI    { rd: usize, rs1: usize, imm: i32 },
    ANDI   { rd: usize, rs1: usize, imm: i32 },
    SLLI   { rd: usize, rs1: usize, shamt: u32 },
    SRLI   { rd: usize, rs1: usize, shamt: u32 },
    SRAI   { rd: usize, rs1: usize, shamt: u32 },
    ADD    { rd: usize, rs1: usize, rs2: usize },
    SUB    { rd: usize, rs1: usize, rs2: usize },
    SLL    { rd: usize, rs1: usize, rs2: usize },
    SLT    { rd: usize, rs1: usize, rs2: usize },
    SLTU   { rd: usize, rs1: usize, rs2: usize },
    XOR    { rd: usize, rs1: usize, rs2: usize },
    SRL    { rd: usize, rs1: usize, rs2: usize },
    SRA    { rd: usize, rs1: usize, rs2: usize },
    OR     { rd: usize, rs1: usize, rs2: usize },
    AND    { rd: usize, rs1: usize, rs2: usize },
    FENCE  { pred: u32, succ: u32 },
    ECALL,
    EBREAK,
}

/// 译码函数：将 32 位的指令原始数据转换为 `Instruction` 枚举。
pub fn decode(inst_data: u32) -> Result<Instruction, SimError> {
    let opcode = inst_data & 0x7F;
    let rd = ((inst_data >> 7) & 0x1F) as usize;
    let rs1 = ((inst_data >> 15) & 0x1F) as usize;
    let rs2 = ((inst_data >> 20) & 0x1F) as usize;
    let funct3 = (inst_data >> 12) & 0x7;
    let funct7 = (inst_data >> 25) & 0x7F;

    match opcode {
        0b0110111 => Ok(Instruction::LUI    { rd, imm: (inst_data & 0xFFFFF000) as i32 }),
        0b0010111 => Ok(Instruction::AUIPC  { rd, imm: (inst_data & 0xFFFFF000) as i32 }),
        0b1101111 => { // JAL
            let imm = (((inst_data >> 31) & 1) << 20) | (((inst_data >> 12) & 0xFF) << 12) | (((inst_data >> 20) & 1) << 11) | (((inst_data >> 21) & 0x3FF) << 1);
            let imm_signed = ((imm as i32) << 11) >> 11;
            Ok(Instruction::JAL { rd, imm: imm_signed })
        }
        0b1100111 => { // JALR
            let imm = (inst_data as i32) >> 20;
            Ok(Instruction::JALR { rd, rs1, imm })
        }
        0b1100011 => { // B-Type
            let imm = (((inst_data >> 31) & 1) << 12) | (((inst_data >> 7) & 1) << 11) | (((inst_data >> 25) & 0x3F) << 5) | (((inst_data >> 8) & 0xF) << 1);
            let imm_signed = ((imm as i32) << 19) >> 19;
            match funct3 {
                0x0 => Ok(Instruction::BEQ  { rs1, rs2, imm: imm_signed }),
                0x1 => Ok(Instruction::BNE  { rs1, rs2, imm: imm_signed }),
                0x4 => Ok(Instruction::BLT  { rs1, rs2, imm: imm_signed }),
                0x5 => Ok(Instruction::BGE  { rs1, rs2, imm: imm_signed }),
                0x6 => Ok(Instruction::BLTU { rs1, rs2, imm: imm_signed }),
                0x7 => Ok(Instruction::BGEU { rs1, rs2, imm: imm_signed }),
                _ => Err(SimError::InvalidInstruction(inst_data)),
            }
        }
        0b0000011 => { // Load
            let imm = (inst_data as i32) >> 20;
            match funct3 {
                0x0 => Ok(Instruction::LB  { rd, rs1, imm }),
                0x1 => Ok(Instruction::LH  { rd, rs1, imm }),
                0x2 => Ok(Instruction::LW  { rd, rs1, imm }),
                0x4 => Ok(Instruction::LBU { rd, rs1, imm }),
                0x5 => Ok(Instruction::LHU { rd, rs1, imm }),
                _ => Err(SimError::InvalidInstruction(inst_data)),
            }
        }
        0b0100011 => { // Store
            let imm = (((inst_data >> 25) & 0x7F) << 5) | ((inst_data >> 7) & 0x1F);
            let imm_signed = ((imm as i32) << 20) >> 20;
            match funct3 {
                0x0 => Ok(Instruction::SB { rs1, rs2, imm: imm_signed }),
                0x1 => Ok(Instruction::SH { rs1, rs2, imm: imm_signed }),
                0x2 => Ok(Instruction::SW { rs1, rs2, imm: imm_signed }),
                _ => Err(SimError::InvalidInstruction(inst_data)),
            }
        }
        0b0010011 => { // I-Type
            let imm = (inst_data as i32) >> 20;
            let shamt = (inst_data >> 20) & 0x1F;
            match funct3 {
                0x0 => Ok(Instruction::ADDI  { rd, rs1, imm }),
                0x2 => Ok(Instruction::SLTI  { rd, rs1, imm }),
                0x3 => Ok(Instruction::SLTIU { rd, rs1, imm }),
                0x4 => Ok(Instruction::XORI  { rd, rs1, imm }),
                0x6 => Ok(Instruction::ORI   { rd, rs1, imm }),
                0x7 => Ok(Instruction::ANDI  { rd, rs1, imm }),
                0x1 => Ok(Instruction::SLLI  { rd, rs1, shamt }),
                0x5 => match funct7 {
                    0x00 => Ok(Instruction::SRLI { rd, rs1, shamt }),
                    0x20 => Ok(Instruction::SRAI { rd, rs1, shamt }),
                    _ => Err(SimError::InvalidInstruction(inst_data)),
                },
                _ => Err(SimError::InvalidInstruction(inst_data)),
            }
        }
        0b0110011 => { // R-Type
            match (funct3, funct7) {
                (0x0, 0x00) => Ok(Instruction::ADD  { rd, rs1, rs2 }),
                (0x0, 0x20) => Ok(Instruction::SUB  { rd, rs1, rs2 }),
                (0x1, 0x00) => Ok(Instruction::SLL  { rd, rs1, rs2 }),
                (0x2, 0x00) => Ok(Instruction::SLT  { rd, rs1, rs2 }),
                (0x3, 0x00) => Ok(Instruction::SLTU { rd, rs1, rs2 }),
                (0x4, 0x00) => Ok(Instruction::XOR  { rd, rs1, rs2 }),
                (0x5, 0x00) => Ok(Instruction::SRL  { rd, rs1, rs2 }),
                (0x5, 0x20) => Ok(Instruction::SRA  { rd, rs1, rs2 }),
                (0x6, 0x00) => Ok(Instruction::OR   { rd, rs1, rs2 }),
                (0x7, 0x00) => Ok(Instruction::AND  { rd, rs1, rs2 }),
                _ => Err(SimError::InvalidInstruction(inst_data)),
            }
        }
        0b0001111 => { // FENCE
            let pred = (inst_data >> 24) & 0xF;
            let succ = (inst_data >> 20) & 0xF;
            Ok(Instruction::FENCE { pred, succ })
        }
        0b1110011 => { // SYSTEM
            match funct3 {
                0x0 => match inst_data >> 20 {
                    0x0 => Ok(Instruction::ECALL),
                    0x1 => Ok(Instruction::EBREAK),
                    _ => Err(SimError::InvalidInstruction(inst_data)),
                },
                _ => Err(SimError::InvalidInstruction(inst_data)),
            }
        }
        _ => Err(SimError::InvalidInstruction(inst_data)),
    }
}